package aes.client;

import java.awt.*;
import java.awt.event.*;
import java.io.*;

import javax.swing.*;
import javax.swing.border.*;
import javax.xml.parsers.*;
import javax.xml.transform.*;
import javax.xml.transform.dom.*;
import javax.xml.transform.stream.*;

import org.w3c.dom.*;
import org.xml.sax.SAXException;

public class SettingsUI extends JPanel implements ActionListener {
	
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	private ClientUI ui;
	private JTextField txtHost;
	private JTextField txtPort;
	private JButton btnSave;
	private JButton btnCancel;
	
	/**
	 * Constructor
	 * 
	 * @param ui Frame object
	 */
	public SettingsUI(ClientUI ui) {
		this.ui = ui;
		
		JFrame frame = new JFrame();
		frame.setSize(340, 255);
		frame.add(this);
		
		setLayout(new GridBagLayout());
		JPanel panel = new JPanel();
		panel.setBorder(new LineBorder(new Color(0, 0, 0), 2, true));
		panel.setSize(300,200);
		
		GridBagConstraints gbc_panel = new GridBagConstraints();
		gbc_panel.insets = new Insets(5, 0, 5, 0);
		gbc_panel.gridx = 0;
		gbc_panel.gridy = 0;
		add(panel,gbc_panel);
		panel.setLayout(new GridBagLayout());
		
		JLabel lblAesLogin = new JLabel("Settings");
		lblAesLogin.setHorizontalAlignment(SwingConstants.CENTER);
		lblAesLogin.setBounds(7, 10, 70, 17);
		lblAesLogin.setFont(new Font("Tahoma", Font.BOLD, 14));
		
		GridBagConstraints gbc_lblAesLogin = new GridBagConstraints();
		gbc_lblAesLogin.gridwidth = 2;
		gbc_lblAesLogin.fill = GridBagConstraints.BOTH;
		gbc_lblAesLogin.insets = new Insets(5, 0, 5, 0);
		gbc_lblAesLogin.gridx = 0;
		gbc_lblAesLogin.gridy = 0;
		panel.add(lblAesLogin, gbc_lblAesLogin);
		
		JLabel lblLogin = new JLabel("Server Host:");
		lblLogin.setHorizontalAlignment(SwingConstants.LEFT);
		lblLogin.setBounds(173, 11, 29, 14);
		GridBagConstraints gbc_lblLogin = new GridBagConstraints();
		gbc_lblLogin.fill = GridBagConstraints.BOTH;
		gbc_lblLogin.insets = new Insets(5, 20, 5, 5);
		gbc_lblLogin.gridx = 0;
		gbc_lblLogin.gridy = 1;
		panel.add(lblLogin, gbc_lblLogin);
		
		txtHost = new JTextField();
		txtHost.setBounds(82, 8, 86, 20);
		GridBagConstraints gbc_txtLogin = new GridBagConstraints();
		gbc_txtLogin.fill = GridBagConstraints.BOTH;
		gbc_txtLogin.insets = new Insets(0, 0, 5, 20);
		gbc_txtLogin.gridx = 1;
		gbc_txtLogin.gridy = 1;
		panel.add(txtHost, gbc_txtLogin);
		txtHost.setColumns(10);
		
		JLabel lblPassword = new JLabel("Server Port:");
		lblPassword.setHorizontalAlignment(SwingConstants.LEFT);
		lblPassword.setBounds(207, 11, 50, 14);
		GridBagConstraints gbc_lblPassword = new GridBagConstraints();
		gbc_lblPassword.fill = GridBagConstraints.BOTH;
		gbc_lblPassword.insets = new Insets(5, 20, 5, 5);
		gbc_lblPassword.gridx = 0;
		gbc_lblPassword.gridy = 2;
		panel.add(lblPassword, gbc_lblPassword);
			
		txtPort = new JTextField();
		txtPort.setBounds(262, 8, 86, 20);
		GridBagConstraints gbc_txtPassword = new GridBagConstraints();
		gbc_txtPassword.fill = GridBagConstraints.BOTH;
		gbc_txtPassword.insets = new Insets(5, 0, 5, 20);
		gbc_txtPassword.gridx = 1;
		gbc_txtPassword.gridy = 2;
		panel.add(txtPort, gbc_txtPassword);
		txtPort.setColumns(5);
		
		btnSave = new JButton("Save", new ImageIcon(SettingsUI.class.getResource("/aes/client/images/Save.png")));
		btnSave.addActionListener(this); 
		GridBagConstraints gbc_btnLogin = new GridBagConstraints();
		gbc_btnLogin.insets = new Insets(5, 20, 10, 10);
		gbc_btnLogin.gridx = 0;
		gbc_btnLogin.gridy = 3;
		panel.add(btnSave, gbc_btnLogin);
		btnSave.setBounds(353, 7, 57, 23);
		
		btnCancel = new JButton("Cancel", new ImageIcon(SettingsUI.class.getResource("/aes/client/images/Cancel.png")));
		btnCancel.addActionListener(this); 
		GridBagConstraints gbc_btnCancel = new GridBagConstraints();
		gbc_btnCancel.insets = new Insets(5, 0, 10, 20);
		gbc_btnCancel.gridx = 1;
		gbc_btnCancel.gridy = 3;
		panel.add(btnCancel, gbc_btnCancel);
		btnCancel.setBounds(353, 7, 57, 23);
	}

	/**
	 * Action Performed event handler
	 */
	@SuppressWarnings("static-access")
	@Override
	public void actionPerformed(ActionEvent arg0) {
		if (arg0.getActionCommand().equals("Save")) {
			// Validate
			if (!validateDomainName(txtHost.getText().trim())) {
				ui.ShowMessageBox("Error", "Wrong server host provided.", JOptionPane.ERROR_MESSAGE);
				return;
			}
			if (!validatePort(txtPort.getText().trim())) {
				ui.ShowMessageBox("Error", "Wrong server port provided.", JOptionPane.ERROR_MESSAGE);
				return;
			}
			if (SaveSettings(txtHost.getText().trim(),Integer.parseInt(txtPort.getText().trim())))
			{
				ui.ShowMessageBox("Message", "Please restart the application to take effect.", JOptionPane.INFORMATION_MESSAGE);
				ui.SetContent(ui.CONNECTOR_SCREEN);
			}
			else
				ui.ShowMessageBox("Error", "Can't save setting to file.", JOptionPane.ERROR_MESSAGE);
		}
		else if (arg0.getActionCommand().equals("Cancel")) {
			ui.ShowLastScreen();
		}
	}
	
	/**
	 * Save settings to XML file
	 * @param host Server host
	 * @param port Server port
	 * @return Save result
	 */
	public boolean SaveSettings(String host, int port) {
		// Save.
		DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
		DocumentBuilder docBuilder;
		try {
			docBuilder = docFactory.newDocumentBuilder();
			// root elements
			Document doc = docBuilder.newDocument();
			Element rootElement = doc.createElement("settings");
			doc.appendChild(rootElement);
			
			// staff elements
			Element server = doc.createElement("server");
			rootElement.appendChild(server);
			
			// firstname elements
			Element host_n = doc.createElement("host");
			host_n.appendChild(doc.createTextNode(host));
			server.appendChild(host_n);
	 
			// lastname elements
			Element port_n = doc.createElement("port");
			port_n.appendChild(doc.createTextNode(Integer.toString(port)));
			server.appendChild(port_n);
			
			// write the content into xml file
			TransformerFactory transformerFactory = TransformerFactory.newInstance();
			Transformer transformer;
			try {
				transformer = transformerFactory.newTransformer();
			} catch (TransformerConfigurationException e) {
				e.printStackTrace();
				return false;
			}
			DOMSource source = new DOMSource(doc);
			StreamResult result = new StreamResult(new File(System.getProperty("user.dir") + "\\AESSettings.xml"));
			
			try {
				transformer.transform(source, result);
			} catch (TransformerException e) {
				e.printStackTrace();
				return false;
			}
			
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
			return false;
		}
		return true;
	}
	
	/**
	 * Load settings from XML file
	 * @param host Server host
	 * @param port Server port
	 * @return Load result
	 */
	public static boolean LoadSettings(String[] host, int[] port) {
		File file = new File(System.getProperty("user.dir") + "\\AESSettings.xml");
	    DocumentBuilder builder;
		try {
			builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
			Document doc = builder.parse(file);
			NodeList nodes = doc.getElementsByTagName("settings");
			if (nodes.getLength() < 1)
				return false;
			nodes = nodes.item(0).getChildNodes();
			
			if (nodes.getLength() < 0)
				return false;
			nodes = nodes.item(0).getChildNodes();
			for (int i=0; i <nodes.getLength(); i++) {
				Element element = (Element) nodes.item(i);
				if (element.getNodeName().equals("host"))
					host[0] = element.getTextContent();
				if (element.getNodeName().equals("port"))
					port[0] = Integer.parseInt(element.getTextContent());
			}
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
			return false;
		} catch (SAXException e) {
			e.printStackTrace();
			return false;
		} catch (IOException e) {
			e.printStackTrace();
			return false;
		}
	    return true;
	}
 
	/**
	 * Bind settings to the textboxes
	 */
	public void BindSettings() {
		String[] host = new String[1];
		host[0] = "localhost";
		int port[] = new int[1];
		port[0] = 5555;
		if (!SettingsUI.LoadSettings(host, port))
		{
			host[0] = "localhost";
			port[0] = 5555;
		}
		txtHost.setText(host[0]);
		txtPort.setText(Integer.toString(port[0]));
	}
	
	/**
	 * Validate host
	 * @param domainName Hostname
	 * @return valid or not
	 */
	public static boolean validateDomainName(String domainName) {
		if((domainName == null) || (domainName.length()>63)) {
			return false;
		}
			return domainName.matches(domainNameRule) && domainName.matches(oneAlpha);
	}
	
	/**
	 * Validate port
	 * @param port Port to validate
	 * @return valid or not
	 */
	public static boolean validatePort(String port) {
		if (port.length() < 1)
			return false;
		int i;
		try {
		i = Integer.parseInt(port);
		}
		catch (Exception e)
		{
			return false;
		}
	    return ((i > 0) && (i < 65535));
	}

	static String domainIdentifier="((\\p{Alnum})([-]|(\\p{Alnum}))*(\\p{Alnum}))|(\\p{Alnum})";
	static String domainNameRule = "("+domainIdentifier + ")((\\.)(" + domainIdentifier+ "))*";
	static String oneAlpha = 
			"^([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\." +
			"([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\." +
			"([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\." +
			"([01]?\\d\\d?|2[0-4]\\d|25[0-5])$";

}
